/**
 * @file    iap_boot.c
 * @brief   BOOT 升级协议
 * @author  name
 * @version 1.0.1
 * @date    2023-05-14
 * 
 * @copyright Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version   <th>Author   <th>Description
 * <tr><td>2023-05-14 <td>1.0.1     <td>name     <td>首次创建
 * </table>
 */
/* includes ------------------------------------------------------------------*/
#include "iap_boot.h"
#include "If_di.h"
#include "boot_param.h"
#include "If_nvm.h"
#include "dev_afe.h"
#include "If_do.h"
#include "If_can.h"
#include "FreeRTOS.h"
#include "task.h"
#include "var_mng.h"
#include "drv_flash.h"
#include "drv_wdg.h"
#include "cfg_prj.h"
#include "param_mng.h"
/* macro/define --------------------------------------------------------------*/
#define FRAME_HAND     (0xDD)
#define FRAME_CMD      (0x02)
#define FRAME_FLAG     (0x12)
#define FRAME_FLAG2    (0x34)
#define FRAME_END      (0x77)

#define FRAME_CAN_UPGRADE   (0x1FFFAAAA) 
/* typedef -------------------------------------------------------------------*/
typedef struct 
{
	uint8_t rate_id;
	uint32_t baudrate;
}rate_map_type;
/* local functions -----------------------------------------------------------*/

/* static variables ----------------------------------------------------------*/
static rate_map_type rate_map_baud[COM_RATE_MAX] = 
{
	{COM_RATE_9600   , 9600   },
	{COM_RATE_14400  , 14400  }, 
	{COM_RATE_19200  , 19200  },
	{COM_RATE_38400  , 38400  },
	{COM_RATE_56000  , 56000  },
	{COM_RATE_57600  , 57600  },
	{COM_RATE_115200 , 115200 },
	{COM_RATE_128000 , 128000 },
	{COM_RATE_230400 , 230400 },
	{COM_RATE_256000 , 256000 },
	{COM_RATE_460800 , 460800 },
	{COM_RATE_500000 , 500000 },
	{COM_RATE_512000 , 512000 },
	{COM_RATE_600000 , 600000 },
	{COM_RATE_750000 , 750000 },
	{COM_RATE_921600 , 921600 },
	{COM_RATE_1000000, 1000000},
	{COM_RATE_1500000, 1500000},
	{COM_RATE_2000000, 2000000},
};

static uint8_t crc32_table_flag = 0;
static uint32_t crc32_table[256] = {0};
/* global variables ----------------------------------------------------------*/
extern TaskHandle_t NvmTask_Handler;
/** ------------------------------------------------------------------------- *
  *                             Global function
 ** ------------------------------------------------------------------------- */
/**
 * @brief  判断是否进入固件升级状态
 * @param  rx_buf
 * @param  rx_len
 * @return uint8_t 
 */
uint8_t is_iap_upgrade_cmd(uint8_t *rx_buf , uint16_t rx_len)
{
    uint8_t res = FALSE;
    uint16_t calc_crc = 0;
    uint16_t recv_crc = 0;
    /** 判断是否为升级指令 */
	if((FRAME_HAND == rx_buf[0]) && (var_get_data(VAR_ID_SELF_ADDR) == rx_buf[1]) && (FRAME_END == rx_buf[rx_len - 1]))
	{
        recv_crc = (rx_buf[rx_len - 3] << 8) + rx_buf[rx_len - 2];
        calc_crc = calc_sum_crc(&rx_buf[1] , rx_len - 4);
		if(recv_crc == calc_crc)
        {
            if((FRAME_CMD == rx_buf[3]) && (FRAME_FLAG == rx_buf[5]))
            {
                res = TRUE;
            }
        }
	}
	else
	{
		
	}

    return res;
}

/**
 * @brief  判断是否进入固件升级状态
 * @param  rx_buf
 * @param  rx_len
 * @return uint8_t 
 */
uint8_t is_iap_upgrade_no_addr_cmd(uint8_t *rx_buf , uint16_t rx_len)
{
    uint8_t res = FALSE;
    uint16_t calc_crc = 0;
    uint16_t recv_crc = 0;
    /** 判断是否为升级指令 */
	if((FRAME_HAND == rx_buf[0]) && (FRAME_END == rx_buf[rx_len - 1]))
	{
        recv_crc = (rx_buf[rx_len - 3] << 8) + rx_buf[rx_len - 2];
        calc_crc = calc_sum_crc(&rx_buf[1] , rx_len - 4);
		if(recv_crc == calc_crc)
        {
            if((FRAME_CMD == rx_buf[3]) && (FRAME_FLAG == rx_buf[5]))
            {
                res = TRUE;
            }
        }
	}
	else
	{
		
	}

    return res;
}

/**
 * @brief  判断是否进入固件升级状态
 * @param  rx_buf
 * @param  rx_len
 * @return uint8_t 
 */
uint8_t is_iap_old_upgrade_cmd(uint8_t *rx_buf , uint16_t rx_len)
{
    uint8_t res = FALSE;
    uint16_t calc_crc = 0;
    uint16_t recv_crc = 0;
    /** 判断是否为升级指令 */
	if((FRAME_HAND == rx_buf[0]) && (0x5A == rx_buf[1]) &&  (FRAME_END == rx_buf[rx_len - 1]))
	{
        recv_crc = (rx_buf[rx_len - 3] << 8) + rx_buf[rx_len - 2];
        calc_crc = calc_sum_crc(&rx_buf[2] , rx_len - 5);
		if(recv_crc == calc_crc)
        {
            if((FRAME_CMD == rx_buf[2]) && (FRAME_FLAG == rx_buf[4]))
            {
                res = TRUE;
            }
        }
	}

    return res;
}

uint8_t is_remote_upgrade_cmd(uint8_t *rx_buf , uint16_t rx_len , uint8_t *tx_buf , uint16_t *tx_num)
{
    uint8_t res = REMOTE_UPGRADE_NULL;
    uint16_t calc_crc = 0;
    uint16_t recv_crc = 0;
	uint16_t tx_idx = 0;
	uint64_t dev_id = 0;
	uint8_t i = 0;

    /** 判断是否为升级指令 */
	if((FRAME_HAND == rx_buf[0]) && (0x5A == rx_buf[1]) && (0xEF == rx_buf[2]) && (FRAME_END == rx_buf[rx_len - 1]))
	{
        recv_crc = (rx_buf[rx_len - 3] << 8) + rx_buf[rx_len - 2];
        calc_crc = calc_sum_crc(&rx_buf[2] , rx_len - 5);
		if(recv_crc == calc_crc)
        {
			for( i =0 ;i < 8; ++ i)
			{
				dev_id += ((uint64_t)rx_buf[i + 4] << (i * 8));
			}
			
            if(var_get_data(VAR_ID_SELF_ADDR) == dev_id)
            {
                res = REMOTE_UPGRADE_SELF;
            }
			else
			{
				res = REMOTE_UPGRADE_S1;
			}
			
			tx_buf[tx_idx ++ ] = FRAME_HAND;
			tx_buf[tx_idx ++ ] = 0xEF;
			tx_buf[tx_idx ++ ] = 0x00;
			tx_buf[tx_idx ++ ] = 0x01;
			if(res != REMOTE_UPGRADE_ERR)
			{
				tx_buf[tx_idx ++ ] = 0x00;
			}
			else
			{
				tx_buf[tx_idx ++ ] = 0x55;
			}
			
			calc_crc = calc_sum_crc(&tx_buf[2] , tx_idx - 2);

			tx_buf[tx_idx ++ ] = calc_crc >> 8;
			tx_buf[tx_idx ++ ] = calc_crc & 0xff;

			tx_buf[tx_idx ++ ] = FRAME_END;
			*tx_num = tx_idx;
        }
	}
	else
	{
		
	}

    return res;
}

uint8_t iap_boot_reply_upgrade_cmd(uint8_t *tx_buf , uint32_t rate ,uint16_t pack_size)
{
	uint16_t calc_crc = 0;
	uint8_t tx_cnt = 0;
	uint8_t i = 0;
	uint8_t rate_id = 0;
	
	tx_buf[tx_cnt ++] = 0xDD;
	tx_buf[tx_cnt ++] = 0x01;
	tx_buf[tx_cnt ++] = 0x02;
	tx_buf[tx_cnt ++] = 0x00;
	tx_buf[tx_cnt ++] = 0x07;
	for( i = 0;i < COM_RATE_MAX; ++ i)
	{
		if(rate_map_baud[i].baudrate == rate)
		{
			rate_id = i;
			break;
		}
	}
	tx_buf[tx_cnt ++] = rate_id;
	tx_buf[tx_cnt ++] = pack_size/32;
	tx_buf[tx_cnt ++] = (APP_MAX_SIZE) >> 8;
	tx_buf[tx_cnt ++] = (APP_MAX_SIZE)&0xff;
	tx_buf[tx_cnt ++] = boot_param_read_par(BP_ID_BOOT_VER);
	tx_buf[tx_cnt ++] = MCU_PTL_TYPE;
	tx_buf[tx_cnt ++] = 0;
	calc_crc = calc_sum_crc(&tx_buf[1] , (tx_cnt - 1));
	tx_buf[tx_cnt ++] = calc_crc >> 8;
	tx_buf[tx_cnt ++] = calc_crc & 0xff;
	tx_buf[tx_cnt ++] = 0x77;
	
	return tx_cnt;
}

uint8_t iap_boot_reply_old_upgrade_cmd(uint8_t *tx_buf , uint32_t rate ,uint16_t pack_size)
{
	uint16_t calc_crc = 0;
	uint8_t tx_cnt = 0;
	uint8_t i = 0;
	uint8_t rate_id = 0;
	
	tx_buf[tx_cnt ++] = 0xDD;
	tx_buf[tx_cnt ++] = 0x02;
	tx_buf[tx_cnt ++] = 0x00;
	tx_buf[tx_cnt ++] = 0x07;
	for( i = 0;i < COM_RATE_MAX; ++ i)
	{
		if(rate_map_baud[i].baudrate == rate)
		{
			rate_id = i;
			break;
		}
	}
	tx_buf[tx_cnt ++] = rate_id;
	tx_buf[tx_cnt ++] = pack_size/32;
	tx_buf[tx_cnt ++] = (APP_MAX_SIZE) >> 8;
	tx_buf[tx_cnt ++] = (APP_MAX_SIZE)&0xff;
	tx_buf[tx_cnt ++] = boot_param_read_par(BP_ID_BOOT_VER);
	tx_buf[tx_cnt ++] = MCU_PTL_TYPE;
	tx_buf[tx_cnt ++] = 0;
	calc_crc = calc_sum_crc(&tx_buf[2] , (tx_cnt - 2));
	tx_buf[tx_cnt ++] = calc_crc >> 8;
	tx_buf[tx_cnt ++] = calc_crc & 0xff;
	tx_buf[tx_cnt ++] = 0x77;
	
	return tx_cnt;
}


uint8_t is_update_reply_slave_cmd(uint8_t *rx_buf , uint16_t rx_len ,uint8_t *tx_buf ,uint16_t *tx_len,uint32_t rate)
{
	if((0xDD == rx_buf[0]) && (0x77 == rx_buf[rx_len-1]))
	{
		
		uint16_t calc_crc = 0;
		uint8_t tx_cnt = 0;
		uint8_t i = 0;
		uint8_t rate_id = 0;
		
		tx_buf[tx_cnt ++] = rx_buf[0];
		tx_buf[tx_cnt ++] = rx_buf[1];
		tx_buf[tx_cnt ++] = rx_buf[2];
		tx_buf[tx_cnt ++] = rx_buf[3];
		tx_buf[tx_cnt ++] = rx_buf[4];
		for( i = 0;i < COM_RATE_MAX; ++ i)
		{
			if(rate_map_baud[i].baudrate == rate)
			{
				rate_id = i;
				break;
			}
		}
		tx_buf[tx_cnt ++] = rate_id;
		tx_buf[tx_cnt ++] = rx_buf[6];
		tx_buf[tx_cnt ++] = rx_buf[7];
		tx_buf[tx_cnt ++] = rx_buf[8];
		tx_buf[tx_cnt ++] = rx_buf[9];
		tx_buf[tx_cnt ++] = rx_buf[10];
		tx_buf[tx_cnt ++] = rx_buf[11];
		calc_crc = calc_sum_crc(&tx_buf[1] , (tx_cnt - 1));
		tx_buf[tx_cnt ++] = calc_crc >> 8;
		tx_buf[tx_cnt ++] = calc_crc & 0xff;
		tx_buf[tx_cnt ++] = 0x77;
		
		*tx_len = tx_cnt;
		
		return TRUE;
	}
	
	return FALSE;
}

uint8_t is_iap_can_upgrade_cmd(can_frame_type recv_msg)
{
	uint8_t res = FALSE;
	if(FRAME_CAN_UPGRADE == recv_msg.id)
	{
		if((recv_msg.data.word_buf[0] == 0x5AA555AA) && (0x8877FF00 == recv_msg.data.word_buf[1]))
		{
			res = TRUE;
		}
	}
	
	return res;
}

void iap_boot_jump_before_deal(uint8_t com_id)
{
	/* 进入休眠状态 */
	vTaskSuspend(NvmTask_Handler);
	
	vTaskDelay(100);

	param_save_use_param();

    boot_param_app_write(com_id);
	
    NVIC_SystemReset();
}

uint8_t is_update_slave_cmd(uint8_t *rx_buf , uint16_t rx_len)
{
    /** 判断是否为升级指令 */
	if((0xBB == rx_buf[0]) && (0xCC == rx_buf[rx_len-1]) && (var_get_data(VAR_ID_SELF_ADDR) != rx_buf[1]))
	{
		return TRUE;
	}
	else if((0xDD == rx_buf[0]) && (0x77 == rx_buf[rx_len-1]) && ((var_get_data(VAR_ID_SELF_ADDR) != rx_buf[1])))
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

void crc32_init_table(void)
{
    uint32_t c;
    uint32_t i, j;
    if (TRUE == crc32_table_flag)
    {
        return;
    }
    for (i = 0; i < 256; ++ i)
    {
        c = i;
        for (j = 0; j < 8; j++)
        {
            if (c & 1)
            {
                c = 0xedb88320L ^ (c >> 1);
            }
            else
            {
                c = c >> 1;
            }
        }
        crc32_table[i] = c;
    }
    crc32_table_flag = TRUE;
}

uint32_t app_calc_app_crc(uint32_t crc, uint32_t app_start ,uint32_t app_size, uint8_t mode)
{
    uint32_t i = 0;
	uint8_t j = 0;
	uint32_t fls_data = {0};
	uint8_t *pdata = (uint8_t *)&fls_data;
	
    crc32_init_table();
	drv_flash_init();
	SYS_UnlockReg(); 
    for (i = 0; i < app_size; i += 4)
    {
		fls_data = FMC_Read(app_start + i);
		for(j =0 ;j < 4; ++ j)
		{
			crc = crc32_table[(crc ^ pdata[j]) & 0xff] ^ (crc >> 8);
		}
		
		if((i % 1000) == 0)
		{
			drv_wdg_feed();
			SYS_UnlockReg();
		}
    }
	
	fls_data = FMC_Read(app_start + i);
	for(j =0 ;j < app_size % 4; ++ j)
	{
		crc = crc32_table[(crc ^ pdata[i]) & 0xff] ^ (crc >> 8);
	}
	
	SYS_LockReg();
	
    if (mode == 0)
    {
        return crc;
    }
    else
    {
        return crc ^ 0xFFFFFFFF;
    }
}

/** ------------------------------------------------------------------------- *
  *                              Local function
 ** ------------------------------------------------------------------------- */
/**
 * @brief  数据校验方法,求和取反加一
 * @param  puchMsg
 * @param  usDataLen
 * @return uint16_t 
 */
uint16_t calc_sum_crc(uint8_t *puchMsg, uint16_t usDataLen)
{
    uint16_t temp_16=0;
    while (usDataLen--) /* 传输消息缓冲区 */
    {
         temp_16 += *puchMsg++ ;
    }
    temp_16=~temp_16;
    temp_16+=1;
    return  temp_16;
}
/********** Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD *********/
